function (check_module REQUIRED MODULE_NAME)
    set(MODULE_SEARCH_PATH ${ARGV})
    list(REMOVE_AT MODULE_SEARCH_PATH 0 1)

    set(MODULE_PATH "")
    set(ORIGIN_MODULE_NAME ${MODULE_NAME})
    string(TOUPPER ${MODULE_NAME} MODULE_NAME)
    if (${MODULE_NAME}_HOME AND NOT "${${MODULE_NAME}_HOME}" STREQUAL "")
        set(MODULE_PATH ${${MODULE_NAME}_HOME})
    elseif (DEFINED ENV{${MODULE_NAME}_HOME} AND NOT "$ENV{${MODULE_NAME}_HOME}" STREQUAL "")
        set(MODULE_PATH $ENV{${MODULE_NAME}_HOME})
    else()
        foreach (DIR ${MODULE_SEARCH_PATH})
            if (DIR AND NOT "${DIR}" STREQUAL "" AND EXISTS ${DIR})
                if (NOT MODULE_PATH OR "${MODULE_PATH}" STREQUAL "")
                    set(MODULE_PATH ${DIR})
                endif()
            endif()
        endforeach()
    endif()
    if (NOT MODULE_PATH OR "${MODULE_PATH}" STREQUAL "" OR NOT EXISTS ${MODULE_PATH})
        set(${MODULE_NAME}_HOME "" CACHE PATH "`${ORIGIN_MODULE_NAME}` module path." FORCE)
        if (REQUIRED)
            message(FATAL_ERROR "`${MODULE_NAME}_HOME` not defined or invalid. You can specify `${MODULE_NAME}_HOME` environment variable or cmake variable to the corresponding path.")
        else()
            message(WARNING "`${MODULE_NAME}_HOME` not defined or invalid. `tfcc` will build without `${ORIGIN_MODULE_NAME}` You can specify `${MODULE_NAME}_HOME` environment variable or cmake variable to the corresponding path.")
        endif()
    else()
        set(${MODULE_NAME}_HOME ${MODULE_PATH} CACHE PATH "`${ORIGIN_MODULE_NAME}` module path." FORCE)
    endif()
endfunction()

function (search_library R_LIST_NAME LIBNAME)
    set(LIBRARY_SEARCH_PATH ${ARGV})
    list(REMOVE_AT LIBRARY_SEARCH_PATH 0 1)
    find_library(${LIBNAME}_LIBRARY_PATH ${LIBNAME} ${LIBRARY_SEARCH_PATH})
    if (${${LIBNAME}_LIBRARY_PATH} MATCHES ".*NOTFOUND")
        message(SEND_ERROR "Library `${LIBNAME}` not found.")
    else()
        set(${R_LIST_NAME} ${${R_LIST_NAME}} ${${LIBNAME}_LIBRARY_PATH} PARENT_SCOPE)
    endif()
endfunction()

function (search_srcs R_LIST_NAME)
    set(SRCS_SEARCH_PATH ${ARGV})
    list(REMOVE_AT SRCS_SEARCH_PATH 0)
    foreach (DIR ${SRCS_SEARCH_PATH})
        aux_source_directory(${DIR} TMP_SRC_FILES)
        set(DIR_ALL_FILES "")
        FILE(GLOB DIR_ALL_FILES ${DIR}/*)
        source_group(${DIR} ${DIR_ALL_FILES})
    endforeach()
    set(${R_LIST_NAME} ${${R_LIST_NAME}} ${TMP_SRC_FILES} PARENT_SCOPE)
endfunction()

function (search_srcs_with_filter FILTER_REGEX R_LIST_NAME)
    set(SRCS_SEARCH_PATH ${ARGV})
    list(REMOVE_AT SRCS_SEARCH_PATH 0 1)
    foreach (DIR ${SRCS_SEARCH_PATH})
        aux_source_directory(${DIR} TMP_SRC_FILES)
        set(DIR_ALL_FILES "")
        FILE(GLOB DIR_ALL_FILES ${DIR}/*)
        source_group(${DIR} ${DIR_ALL_FILES})
    endforeach()
    list(FILTER TMP_SRC_FILES INCLUDE REGEX ${FILTER_REGEX})
    set(${R_LIST_NAME} ${${R_LIST_NAME}} ${TMP_SRC_FILES} PARENT_SCOPE)
endfunction()

